/*
 * Copyright (C) 2004 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.swing.text;

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;

/**
 * A non-editable text area that has some convinience methods to write text in
 * different colors. Used for example as a simple output console.
 * 
 * @author $Author: johan $
 * @version $Revision: 1.3 $
 */
@SuppressWarnings("serial")
public class ConsoleBean extends JComponent
{
	private final static String DEFAULT_STYLE_NAME = "default";
	private final static String WARN_STYLE_NAME = "warn";
	private final static String ERROR_STYLE_NAME = "error";
	private final static String INFO_STYLE_NAME = "info";

	private BorderLayout mainLayout = new BorderLayout();
	private JScrollPane contentScrollPane = new JScrollPane();
	private JTextPane textPane = new JTextPane();
	private DefaultStyledDocument document;
	private java.awt.Color warningColor = java.awt.Color.PINK;
	private java.awt.Color errorColor = java.awt.Color.RED;
	private java.awt.Color defaultColor = java.awt.Color.BLACK;
	private java.awt.Color infoColor = java.awt.Color.GREEN;

	/**
	 * Initialize a console bean. The constructor is not thread safe and must be
	 * invoked on the AWT/Swing event queue.
	 * 
	 * @see EventQueue
	 */
	public ConsoleBean() {
		initialize();
	}

	private void initialize()
	{
		setLayout(mainLayout);
		textPane.setEditable(false);
		textPane.setContentType("text/plain");
		Document doc = textPane.getDocument();
		if (doc instanceof DefaultStyledDocument) {
			document = (DefaultStyledDocument) doc;
			setupStyles();
			add(contentScrollPane, BorderLayout.CENTER);
			contentScrollPane.getViewport().add(textPane);
		} else {
			add(new JLabel("E R R O R: Unable to create default document"));
		}
	}

	private void setupStyles()
	{
		document.removeStyle(DEFAULT_STYLE_NAME);
		Style defaultStyle = document.addStyle(DEFAULT_STYLE_NAME, null);
		StyleConstants.setForeground(defaultStyle, defaultColor);

		document.removeStyle(WARN_STYLE_NAME);
		Style warningStyle = document.addStyle(WARN_STYLE_NAME, defaultStyle);
		StyleConstants.setForeground(warningStyle, warningColor);

		document.removeStyle(ERROR_STYLE_NAME);
		Style errorStyle = document.addStyle(ERROR_STYLE_NAME, defaultStyle);
		StyleConstants.setForeground(errorStyle, errorColor);

		document.removeStyle(INFO_STYLE_NAME);
		Style infoStyle = document.addStyle(INFO_STYLE_NAME, defaultStyle);
		StyleConstants.setForeground(infoStyle, infoColor);
	}

	/**
	 * Print a message on the console in the default color. This method is
	 * thread safe and can be called from any thread.
	 * 
	 * @see #setDefaultColor(java.awt.Color)
	 * @param message
	 *            The text to display.
	 */
	public void println(String message)
	{
		print(message + "\n");
	}

	/**
	 * Print a message on the console in the default color. This method is
	 * thread safe and can be called from any thread.
	 * 
	 * @see #setDefaultColor(java.awt.Color)
	 * @param message
	 *            The text to display.
	 */
	public void print(String message)
	{
		append(message, DEFAULT_STYLE_NAME);
	}

	/**
	 * Print a message on the console using the warning color. This method is
	 * thread safe and can be called from any thread.
	 * 
	 * @see #setWarningColor(java.awt.Color)
	 * @param message
	 *            The text to display. The console bean will add a line break
	 *            after the message.
	 */
	public void warn(String message)
	{
		append(message + " \n", WARN_STYLE_NAME);
	}

	/**
	 * Print a message on the console using the error color. This method is
	 * thread safe and can be called from any thread.
	 * 
	 * @see #setErrorColor(java.awt.Color)
	 * @param message
	 *            The text to display. The console bean will add a line break
	 *            after the message.
	 */
	public void error(String message)
	{
		append(message + "\n", ERROR_STYLE_NAME);
	}

	/**
	 * Print a message on the console using the information color. This method
	 * is thread safe and can be called from any thread.
	 * 
	 * @see #setInfoColor(java.awt.Color)
	 * @param message
	 *            The text to display. The console bean will <emp>not </emp> add
	 *            a line break after the message.
	 */
	public void info(String message)
	{
		append(message, INFO_STYLE_NAME);
	}

	private void append(final String message, final String styleName)
	{
		EventQueue.invokeLater(new Runnable() {
			public void run()
			{
				Style style = document.getStyle(styleName);
				try {
					document.insertString(
							document.getEndPosition().getOffset() - 1, message,
							style);
				} catch (BadLocationException exc) {
					exc.printStackTrace();
				}
			}
		});
	}

	/**
	 * Get the color used to write warnings.
	 * 
	 * @return The color used to print warning text.
	 */
	public java.awt.Color getWarningColor()
	{
		return warningColor;
	}

	/**
	 * Set the color used to print warning text. This method is not thread safe
	 * and must be invoked on the AWT/Swing Event thread.
	 * 
	 * @see EventQueue#isDispatchThread()
	 * @param warningColor
	 *            The color to be used for warning text.
	 */
	public void setWarningColor(java.awt.Color warningColor)
	{
		this.warningColor = warningColor;
		setupStyles();
	}

	/**
	 * Get the color used to write errors.
	 * 
	 * @return The color used to print error text.
	 */
	public java.awt.Color getErrorColor()
	{
		return errorColor;
	}

	/**
	 * Set the color used to print error text. This method is not thread safe
	 * and must be invoked on the AWT/Swing Event thread.
	 * 
	 * @see EventQueue#isDispatchThread()
	 * @param errorColor
	 *            The color to be used to print error text.
	 */
	public void setErrorColor(java.awt.Color errorColor)
	{
		this.errorColor = errorColor;
		setupStyles();
	}

	/**
	 * Get the color used to write text.
	 * 
	 * @return The color used to print text.
	 */
	public java.awt.Color getDefaultColor()
	{
		return defaultColor;
	}

	/**
	 * Set the color used to print text. This method is not thread safe and must
	 * be invoked on the AWT/Swing Event thread.
	 * 
	 * @see EventQueue#isDispatchThread()
	 * @param defaultColor
	 *            The color to be used to print text.
	 */
	public void setDefaultColor(java.awt.Color defaultColor)
	{
		this.defaultColor = defaultColor;
		setupStyles();
	}

	/**
	 * Get the color used to write information text.
	 * 
	 * @return The color used to print information text.
	 */
	public java.awt.Color getInfoColor()
	{
		return infoColor;
	}

	/**
	 * Set the color used to print information text. This method is not thread
	 * safe and must be invoked on the AWT/Swing Event thread.
	 * 
	 * @see EventQueue#isDispatchThread()
	 * @param infoColor
	 *            The color to be used to print information text.
	 */
	public void setInfoColor(java.awt.Color infoColor)
	{
		this.infoColor = infoColor;
		setupStyles();
	}

}